﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using l1cs.server.templates;
using l1cs.server.serverpackets;
using l1cs.server.datatables;
using l1cs.server.utils;
using l1cs.server.model.skill;
using System.Threading;
using System.Collections;

namespace l1cs.server.model.Instance
{
    public class L1MonsterInstance : L1NpcInstance
    {
        private static Logger _log = Logger.getLogger( typeof( L1MonsterInstance ).FullName );

        private static Random _random = new Random();

        private bool _storeDroped; // ドロップアイテムの読込が完了したか

        // アイテム使用処理
        override public void onItemUse()
        {
            if ( !isActived() && _target != null )
            {
                useItem( USEITEM_HASTE, 40 ); // ４０％の確率でヘイストポーション使用

                // アイテムじゃないけどドッペル処理
                if ( getNpcTemplate().is_doppel() && _target is L1PcInstance )
                {
                    L1PcInstance targetPc = (L1PcInstance)_target;
                    setName( _target.getName() );
                    setNameId( _target.getName() );
                    setTitle( _target.getTitle() );
                    setTempLawful( _target.getLawful() );
                    setTempCharGfx( targetPc.getClassId() );
                    setGfxId( targetPc.getClassId() );
                    setPassispeed( 640 );
                    setAtkspeed( 900 ); // 正確な値がわからん
                    foreach ( L1PcInstance pc in L1World.getInstance()
                            .getRecognizePlayer( this ) )
                    {
                        pc.sendPackets( new S_RemoveObject( this ) );
                        pc.removeKnownObject( this );
                        pc.updateObject();
                    }
                }
            }
            if ( getCurrentHp() * 100 / getMaxHp() < 40 )
            { // ＨＰが４０％きったら
                useItem( USEITEM_HEAL, 50 ); // ５０％の確率で回復ポーション使用
            }
        }

        override public void onPerceive( L1PcInstance perceivedFrom )
        {
            perceivedFrom.addKnownObject( this );
            if ( 0 < getCurrentHp() )
            {
                if ( getHiddenStatus() == HIDDEN_STATUS_SINK
                        || getHiddenStatus() == HIDDEN_STATUS_ICE )
                {
                    perceivedFrom.sendPackets( new S_DoActionGFX( getId(),
                            ActionCodes.ACTION_Hide ) );
                }
                else if ( getHiddenStatus() == HIDDEN_STATUS_FLY )
                {
                    perceivedFrom.sendPackets( new S_DoActionGFX( getId(),
                            ActionCodes.ACTION_Moveup ) );
                }
                perceivedFrom.sendPackets( new S_NPCPack( this ) );
                onNpcAI(); // モンスターのＡＩを開始
                if ( getBraveSpeed() == 1 )
                { // ちゃんとした方法がわからない
                    perceivedFrom.sendPackets( new S_SkillBrave( getId(), 1, 600000 ) );
                }
            }
            else
            {
                perceivedFrom.sendPackets( new S_NPCPack( this ) );
            }
        }

        // ターゲットを探す
        public static int[,] _classGfxId = { 
                    { 0, 1 }, { 48, 61 }, { 37, 138 },
                    { 734, 1186 }, { 2786, 2796 } };

        override public void searchTarget()
        {
            // ターゲット捜索
            L1PcInstance targetPlayer = null;

            foreach ( L1PcInstance pc in L1World.getInstance().getVisiblePlayer( this ) )
            {
                if ( pc.getCurrentHp() <= 0 || pc.isDead() || pc.isGm()
                        || pc.isMonitor() || pc.isGhost() )
                {
                    continue;
                }

                // 闘技場内は変身／未変身に限らず全てアクティブ
                int mapId = getMapId();
                if ( mapId == 88 || mapId == 98 || mapId == 92 || mapId == 91
                        || mapId == 95 )
                {
                    if ( !pc.isInvisble() || getNpcTemplate().is_agrocoi() )
                    { // インビジチェック
                        targetPlayer = pc;
                        break;
                    }
                }

                if ( getNpcId() == 45600 )
                { // カーツ
                    if ( pc.isCrown() || pc.isDarkelf()
                            || pc.getTempCharGfx() != pc.getClassId() )
                    { // 未変身の君主、DEにはアクティブ
                        targetPlayer = pc;
                        break;
                    }
                }

                // どちらかの条件を満たす場合、友好と見なされ先制攻撃されない。
                // ・モンスターのカルマがマイナス値（バルログ側モンスター）でPCのカルマレベルが1以上（バルログ友好）
                // ・モンスターのカルマがプラス値（ヤヒ側モンスター）でPCのカルマレベルが-1以下（ヤヒ友好）
                if ( ( getNpcTemplate().getKarma() < 0 && pc.getKarmaLevel() >= 1 )
                        || ( getNpcTemplate().getKarma() > 0 && pc.getKarmaLevel() <= -1 ) )
                {
                    continue;
                }
                // 見棄てられた者たちの地 カルマクエストの変身中は、各陣営のモンスターから先制攻撃されない
                if ( pc.getTempCharGfx() == 6034 && getNpcTemplate().getKarma() < 0
                        || pc.getTempCharGfx() == 6035 && getNpcTemplate().getKarma() > 0
                        || pc.getTempCharGfx() == 6035 && getNpcTemplate().get_npcId() == 46070
                        || pc.getTempCharGfx() == 6035 && getNpcTemplate().get_npcId() == 46072 )
                {
                    continue;
                }

                if ( !getNpcTemplate().is_agro() && !getNpcTemplate().is_agrososc()
                        && getNpcTemplate().is_agrogfxid1() < 0
                        && getNpcTemplate().is_agrogfxid2() < 0 )
                { // 完全なノンアクティブモンスター
                    if ( pc.getLawful() < -1000 )
                    { // プレイヤーがカオティック
                        targetPlayer = pc;
                        break;
                    }
                    continue;
                }

                if ( !pc.isInvisble() || getNpcTemplate().is_agrocoi() )
                { // インビジチェック
                    if ( pc.hasSkillEffect( 67 ) )
                    { // 変身してる
                        if ( getNpcTemplate().is_agrososc() )
                        { // 変身に対してアクティブ
                            targetPlayer = pc;
                            break;
                        }
                    }
                    else if ( getNpcTemplate().is_agro() )
                    { // アクティブモンスター
                        targetPlayer = pc;
                        break;
                    }

                    // 特定のクラスorグラフィックＩＤにアクティブ
                    if ( getNpcTemplate().is_agrogfxid1() >= 0
                            && getNpcTemplate().is_agrogfxid1() <= 4 )
                    { // クラス指定
                        if ( _classGfxId[getNpcTemplate().is_agrogfxid1(), 0] == pc
                                .getTempCharGfx()
                                || _classGfxId[getNpcTemplate().is_agrogfxid1(), 1] == pc
                                        .getTempCharGfx() )
                        {
                            targetPlayer = pc;
                            break;
                        }
                    }
                    else if ( pc.getTempCharGfx() == getNpcTemplate()
                          .is_agrogfxid1() )
                    { // グラフィックＩＤ指定
                        targetPlayer = pc;
                        break;
                    }

                    if ( getNpcTemplate().is_agrogfxid2() >= 0
                            && getNpcTemplate().is_agrogfxid2() <= 4 )
                    { // クラス指定
                        if ( _classGfxId[getNpcTemplate().is_agrogfxid2(), 0] == pc
                                .getTempCharGfx()
                                || _classGfxId[getNpcTemplate().is_agrogfxid2(), 1] == pc
                                        .getTempCharGfx() )
                        {
                            targetPlayer = pc;
                            break;
                        }
                    }
                    else if ( pc.getTempCharGfx() == getNpcTemplate()
                          .is_agrogfxid2() )
                    { // グラフィックＩＤ指定
                        targetPlayer = pc;
                        break;
                    }
                }
            }
            if ( targetPlayer != null )
            {
                _hateList.add( targetPlayer, 0 );
                _target = targetPlayer;
            }
        }

        // リンクの設定
        override public void setLink( L1Character cha )
        {
            if ( cha != null && _hateList.isEmpty() )
            { // ターゲットがいない場合のみ追加
                _hateList.add( cha, 0 );
                checkTarget();
            }
        }

        public L1MonsterInstance( L1Npc template )
            : base( template )
        {
            _storeDroped = false;
        }

        override public void onNpcAI()
        {
            if ( isAiRunning() )
            {
                return;
            }
            if ( !_storeDroped ) // 無駄なオブジェクトＩＤを発行しないようにここでセット
            {
                DropTable.getInstance().setDrop( this, getInventory() );
                getInventory().shuffle();
                _storeDroped = true;
            }
            setActived( false );
            startAI();
        }

        override public void onTalkAction( L1PcInstance pc )
        {
            int objid = getId();
            L1NpcTalkData talking = NPCTalkDataTable.getInstance().getTemplate(
                    getNpcTemplate().get_npcId() );
            String htmlid = null;
            String[] htmldata = null;

            // html表示パケット送信
            if ( htmlid != null )
            { // htmlidが指定されている場合
                if ( htmldata != null )
                { // html指定がある場合は表示
                    pc.sendPackets( new S_NPCTalkReturn( objid, htmlid,
                            htmldata ) );
                }
                else
                {
                    pc.sendPackets( new S_NPCTalkReturn( objid, htmlid ) );
                }
            }
            else
            {
                if ( pc.getLawful() < -1000 )
                { // プレイヤーがカオティック
                    pc.sendPackets( new S_NPCTalkReturn( talking, objid, 2 ) );
                }
                else
                {
                    pc.sendPackets( new S_NPCTalkReturn( talking, objid, 1 ) );
                }
            }
        }

        override public void onAction( L1PcInstance pc )
        {
            if ( getCurrentHp() > 0 && !isDead() )
            {
                L1Attack attack = new L1Attack( pc, this );
                if ( attack.calcHit() )
                {
                    attack.calcDamage();
                    attack.calcStaffOfMana();
                    attack.addPcPoisonAttack( pc, this );
                    attack.addChaserAttack();
                }
                attack.action();
                attack.commit();
            }
        }

        override public void ReceiveManaDamage( L1Character attacker, int mpDamage )
        { // 攻撃でＭＰを減らすときはここを使用
            if ( mpDamage > 0 && !isDead() )
            {
                // int Hate = mpDamage / 10 + 10; // 注意！計算適当 ダメージの１０分の１＋ヒットヘイト１０
                // setHate(attacker, Hate);
                setHate( attacker, mpDamage );

                onNpcAI();

                if ( attacker is L1PcInstance )
                { // 仲間意識をもつモンスターのターゲットに設定
                    serchLink( (L1PcInstance)attacker, getNpcTemplate()
                            .get_family() );
                }

                int newMp = getCurrentMp() - mpDamage;
                if ( newMp < 0 )
                {
                    newMp = 0;
                }
                setCurrentMp( newMp );
            }
        }

        override public void receiveDamage( L1Character attacker, int damage )
        { // 攻撃でＨＰを減らすときはここを使用
            if ( getCurrentHp() > 0 && !isDead() )
            {
                if ( getHiddenStatus() == HIDDEN_STATUS_SINK
                        || getHiddenStatus() == HIDDEN_STATUS_FLY )
                {
                    return;
                }
                if ( damage >= 0 )
                {
                    if ( !( attacker is L1EffectInstance ) )
                    { // FWはヘイトなし
                        setHate( attacker, damage );
                    }
                }
                if ( damage > 0 )
                {
                    removeSkillEffect( L1SkillId.FOG_OF_SLEEPING );
                }

                onNpcAI();

                if ( attacker is L1PcInstance )
                { // 仲間意識をもつモンスターのターゲットに設定
                    serchLink( (L1PcInstance)attacker, getNpcTemplate()
                            .get_family() );
                }

                if ( attacker is L1PcInstance && damage > 0 )
                {
                    L1PcInstance player = (L1PcInstance)attacker;
                    player.setPetTarget( this );

                    if ( getNpcTemplate().get_npcId() == 45681 // リンドビオル
                            || getNpcTemplate().get_npcId() == 45682 // アンタラス
                            || getNpcTemplate().get_npcId() == 45683 // パプリオン
                            || getNpcTemplate().get_npcId() == 45684 ) // ヴァラカス
                    {
                        recall( player );
                    }
                }

                int newHp = getCurrentHp() - damage;
                if ( newHp <= 0 && !isDead() )
                {
                    int transformId = getNpcTemplate().getTransformId();
                    // 変身しないモンスター
                    if ( transformId == -1 )
                    {
                        setCurrentHpDirect( 0 );
                        setDead( true );
                        setStatus( ActionCodes.ACTION_Die );
                        openDoorWhenNpcDied( this );
                        // TODO 優先度9 スレッドプール
                        //Death death = new Death( attacker );
                        //GeneralThreadPool.getInstance().execute( death );
                        new Timer( new TimerCallback( DeathTimerSub ), attacker, 0, Timeout.Infinite );
                        // Death(attacker);
                    }
                    else
                    { // 変身するモンスター
                        // distributeExpDropKarma(attacker);
                        transform( transformId );
                    }
                }
                if ( newHp > 0 )
                {
                    setCurrentHp( newHp );
                    hide();
                }
            }
            else if ( !isDead() )
            { // 念のため
                setDead( true );
                setStatus( ActionCodes.ACTION_Die );
                //Death death = new Death( attacker );
                //GeneralThreadPool.getInstance().execute( death );
                new Timer( new TimerCallback( DeathTimerSub ), attacker, 0, Timeout.Infinite );
                // Death(attacker);
            }
        }

        private static void openDoorWhenNpcDied( L1NpcInstance npc )
        {
            int[] npcId = { 46143, 46144, 46145, 46146, 46147, 46148,
                        46149, 46150, 46151, 46152};
            int[] doorId = { 5001, 5002, 5003, 5004, 5005, 5006,
                        5007, 5008, 5009, 5010};

            for ( int i = 0; i < npcId.Length; i++ )
            {
                if ( npc.getNpcTemplate().get_npcId() == npcId[i] )
                {
                    openDoorInCrystalCave( doorId[i] );
                }
            }
        }

        private static void openDoorInCrystalCave( int doorId )
        {
            foreach ( L1Object l1object in L1World.getInstance().getObject() )
            {
                if ( l1object is L1DoorInstance )
                {
                    L1DoorInstance door = (L1DoorInstance)l1object;
                    if ( door.getDoorId() == doorId )
                    {
                        door.open();
                    }
                }
            }
        }

        /**
         * 距離が5以上離れているpcを距離3～4の位置に引き寄せる。
         * 
         * @param pc
         */
        private void recall( L1PcInstance pc )
        {
            if ( getMapId() != pc.getMapId() )
            {
                return;
            }
            if ( getLocation().getTileLineDistance( pc.getLocation() ) > 4 )
            {
                for ( int count = 0; count < 10; count++ )
                {
                    L1Location newLoc = getLocation().randomLocation( 3, 4, false );
                    if ( glanceCheck( newLoc.getX(), newLoc.getY() ) )
                    {
                        L1Teleport.teleport( pc, newLoc.getX(), newLoc.getY(),
                                getMapId(), 5, true );
                        break;
                    }
                }
            }
        }

        override public void setCurrentHp( int i )
        {
            int currentHp = i;
            if ( currentHp >= getMaxHp() )
            {
                currentHp = getMaxHp();
            }
            setCurrentHpDirect( currentHp );

            if ( getMaxHp() > getCurrentHp() )
            {
                startHpRegeneration();
            }
        }

        override public void setCurrentMp( int i )
        {
            int currentMp = i;
            if ( currentMp >= getMaxMp() )
            {
                currentMp = getMaxMp();
            }
            setCurrentMpDirect( currentMp );

            if ( getMaxMp() > getCurrentMp() )
            {
                startMpRegeneration();
            }
        }

        //class Death  {
        //    L1Character _lastAttacker;

        //    public Death(L1Character lastAttacker) {
        //        _lastAttacker = lastAttacker;
        //    }

        public void DeathTimerSub( object state )
        {
            setDeathProcessing( true );
            setCurrentHpDirect( 0 );
            setDead( true );
            setStatus( ActionCodes.ACTION_Die );

            getMap().setPassable( getLocation(), true );

            broadcastPacket( new S_DoActionGFX( getId(), ActionCodes.ACTION_Die ) );

            startChat( CHAT_TIMING_DEAD );

            distributeExpDropKarma( (L1Character)state );
            giveUbSeal();

            setDeathProcessing( false );

            setExp( 0 );
            setKarma( 0 );
            allTargetClear();

            startDeleteTimer();
        }
        // }

        private void distributeExpDropKarma( L1Character lastAttacker )
        {
            if ( lastAttacker == null )
            {
                return;
            }
            L1PcInstance pc = null;
            if ( lastAttacker is L1PcInstance )
            {
                pc = (L1PcInstance)lastAttacker;
            }
            else if ( lastAttacker is L1PetInstance )
            {
                pc = (L1PcInstance)( (L1PetInstance)lastAttacker ).getMaster();
            }
            else if ( lastAttacker is L1SummonInstance )
            {
                pc = (L1PcInstance)( (L1SummonInstance)lastAttacker ).getMaster();
            }

            if ( pc != null )
            {
                ArrayList targetList = new ArrayList();
                foreach ( L1Character chara in _hateList.toTargetArrayList() )
                {
                    targetList.Add( chara );
                }
                List<int> hateList = _hateList.toHateArrayList();
                int exp = getExp();
                CalcExp.calcExp(
                    pc, getId(), targetList, hateList, exp );
                // 死亡した場合はドロップとカルマも分配、死亡せず変身した場合はEXPのみ
                if ( isDead() )
                {
                    distributeDrop();
                    giveKarma( pc );
                }
            }
            else if ( lastAttacker is L1EffectInstance )
            { // FWが倒した場合
                ArrayList targetList = new ArrayList();
                foreach ( L1Character chara in _hateList.toTargetArrayList() )
                {
                    targetList.Add( chara );
                }
                List<int> hateList = _hateList.toHateArrayList();
                // ヘイトリストにキャラクターが存在する
                if ( hateList.Count != 0 )
                {
                    // 最大ヘイトを持つキャラクターが倒したものとする
                    int maxHate = 0;
                    for ( int i = hateList.Count - 1; i >= 0; i-- )
                    {
                        if ( maxHate < hateList[i] )
                        {
                            maxHate = ( hateList[i] );
                            lastAttacker = (L1Character)targetList[i];
                        }
                    }
                    if ( lastAttacker is L1PcInstance )
                    {
                        pc = (L1PcInstance)lastAttacker;
                    }
                    else if ( lastAttacker is L1PetInstance )
                    {
                        pc = (L1PcInstance)( (L1PetInstance)lastAttacker ).getMaster();
                    }
                    else if ( lastAttacker is L1SummonInstance )
                    {
                        pc = (L1PcInstance)( (L1SummonInstance)lastAttacker ).getMaster();
                    }
                    if ( pc != null )
                    {
                        int exp = getExp();
                        CalcExp.calcExp( pc, getId(), targetList, hateList, exp );
                        // 死亡した場合はドロップとカルマも分配、死亡せず変身した場合はEXPのみ
                        if ( isDead() )
                        {
                            distributeDrop();
                            giveKarma( pc );
                        }
                    }
                }
            }
        }

        private void distributeDrop()
        {
            List<L1Character> dropTargetList = _dropHateList.toTargetArrayList();
            List<int> dropHateList = _dropHateList.toHateArrayList();
            int npcId = getNpcTemplate().get_npcId();
            if ( npcId != 45640
                    || ( npcId == 45640 && getTempCharGfx() == 2332 ) )
            {
                DropTable.getInstance().dropShare( this, dropTargetList, dropHateList );
            }
        }

        private void giveKarma( L1PcInstance pc )
        {
            int karma = getKarma();
            if ( karma != 0 )
            {
                int karmaSign = Math.Sign( karma );
                int pcKarmaLevel = pc.getKarmaLevel();
                int pcKarmaLevelSign = Math.Sign( pcKarmaLevel );
                // カルマ背信行為は5倍
                if ( pcKarmaLevelSign != 0 && karmaSign != pcKarmaLevelSign )
                {
                    karma *= 5;
                }
                // カルマは止めを刺したプレイヤーに設定。ペットorサモンで倒した場合も入る。
                pc.addKarma( (int)( karma * Config.RATE_KARMA ) );
            }
        }

        private void giveUbSeal()
        {
            if ( getUbSealCount() != 0 )
            { // UBの勇者の証
                L1UltimateBattle ub = UBTable.getInstance().getUb( getUbId() );
                if ( ub != null )
                {
                    foreach ( L1PcInstance pc in ub.getMembersArray() )
                    {
                        if ( pc != null && !pc.isDead() && !pc.isGhost() )
                        {
                            L1ItemInstance item = pc.getInventory()
                                    .storeItem( 41402, getUbSealCount() );
                            pc.sendPackets( new S_ServerMessage( 403, item
                                    .getLogName() ) ); // %0を手に入れました。
                        }
                    }
                }
            }
        }

        public bool is_storeDroped()
        {
            return _storeDroped;
        }

        public void set_storeDroped( bool flag )
        {
            _storeDroped = flag;
        }

        private int _ubSealCount = 0; // UBで倒された時、参加者に与えられる勇者の証の個数

        public int getUbSealCount()
        {
            return _ubSealCount;
        }

        public void setUbSealCount( int i )
        {
            _ubSealCount = i;
        }

        private int _ubId = 0; // UBID

        public int getUbId()
        {
            return _ubId;
        }

        public void setUbId( int i )
        {
            _ubId = i;
        }

        private void hide()
        {
            int npcid = getNpcTemplate().get_npcId();
            if ( npcid == 45061 // カーズドスパルトイ
                    || npcid == 45161 // スパルトイ
                    || npcid == 45181 // スパルトイ
                    || npcid == 45455 )
            { // デッドリースパルトイ
                if ( getMaxHp() / 3 > getCurrentHp() )
                {
                    int rnd = _random.Next( 10 );
                    if ( 1 > rnd )
                    {
                        allTargetClear();
                        setHiddenStatus( HIDDEN_STATUS_SINK );
                        broadcastPacket( new S_DoActionGFX( getId(),
                                ActionCodes.ACTION_Hide ) );
                        setStatus( 13 );
                        broadcastPacket( new S_NPCPack( this ) );
                    }
                }
            }
            else if ( npcid == 45682 )
            { // アンタラス
                if ( getMaxHp() / 3 > getCurrentHp() )
                {
                    int rnd = _random.Next( 50 );
                    if ( 1 > rnd )
                    {
                        allTargetClear();
                        setHiddenStatus( HIDDEN_STATUS_SINK );
                        broadcastPacket( new S_DoActionGFX( getId(),
                                ActionCodes.ACTION_AntharasHide ) );
                        setStatus( 20 );
                        broadcastPacket( new S_NPCPack( this ) );
                    }
                }
            }
            else if ( npcid == 45067 // バレーハーピー
                  || npcid == 45264 // ハーピー
                  || npcid == 45452 // ハーピー
                  || npcid == 45090 // バレーグリフォン
                  || npcid == 45321 // グリフォン
                  || npcid == 45445 )
            { // グリフォン
                if ( getMaxHp() / 3 > getCurrentHp() )
                {
                    int rnd = _random.Next( 10 );
                    if ( 1 > rnd )
                    {
                        allTargetClear();
                        setHiddenStatus( HIDDEN_STATUS_FLY );
                        broadcastPacket( new S_DoActionGFX( getId(),
                                ActionCodes.ACTION_Moveup ) );
                        setStatus( 4 );
                        broadcastPacket( new S_NPCPack( this ) );
                    }
                }
            }
            else if ( npcid == 45681 )
            { // リンドビオル
                if ( getMaxHp() / 3 > getCurrentHp() )
                {
                    int rnd = _random.Next( 50 );
                    if ( 1 > rnd )
                    {
                        allTargetClear();
                        setHiddenStatus( HIDDEN_STATUS_FLY );
                        broadcastPacket( new S_DoActionGFX( getId(),
                                ActionCodes.ACTION_Moveup ) );
                        setStatus( 11 );
                        broadcastPacket( new S_NPCPack( this ) );
                    }
                }
            }
            else if ( npcid == 46107 // テーベ マンドラゴラ(白)
                   || npcid == 46108 )
            { // テーベ マンドラゴラ(黒)
                if ( getMaxHp() / 4 > getCurrentHp() )
                {
                    int rnd = _random.Next( 10 );
                    if ( 1 > rnd )
                    {
                        allTargetClear();
                        setHiddenStatus( HIDDEN_STATUS_SINK );
                        broadcastPacket( new S_DoActionGFX( getId(),
                                ActionCodes.ACTION_Hide ) );
                        setStatus( 13 );
                        broadcastPacket( new S_NPCPack( this ) );
                    }
                }
            }
        }

        public void initHide()
        {
            // 出現直後の隠れる動作
            // 潜るMOBは一定の確率で地中に潜った状態に、
            // 飛ぶMOBは飛んだ状態にしておく
            int npcid = getNpcTemplate().get_npcId();
            if ( npcid == 45061 // カーズドスパルトイ
                    || npcid == 45161 // スパルトイ
                    || npcid == 45181 // スパルトイ
                    || npcid == 45455 )
            { // デッドリースパルトイ
                int rnd = _random.Next( 3 );
                if ( 1 > rnd )
                {
                    setHiddenStatus( HIDDEN_STATUS_SINK );
                    setStatus( 13 );
                }
            }
            else if ( npcid == 45045 // クレイゴーレム
                  || npcid == 45126 // ストーンゴーレム
                  || npcid == 45134 // ストーンゴーレム
                  || npcid == 45281 )
            { // ギランストーンゴーレム
                int rnd = _random.Next( 3 );
                if ( 1 > rnd )
                {
                    setHiddenStatus( HIDDEN_STATUS_SINK );
                    setStatus( 4 );
                }
            }
            else if ( npcid == 45067 // バレーハーピー
                  || npcid == 45264 // ハーピー
                  || npcid == 45452 // ハーピー
                  || npcid == 45090 // バレーグリフォン
                  || npcid == 45321 // グリフォン
                  || npcid == 45445 )
            { // グリフォン
                setHiddenStatus( HIDDEN_STATUS_FLY );
                setStatus( 4 );
            }
            else if ( npcid == 45681 )
            { // リンドビオル
                setHiddenStatus( HIDDEN_STATUS_FLY );
                setStatus( 11 );
            }
            else if ( npcid == 46107 // テーベ マンドラゴラ(白)
                   || npcid == 46108 )
            { // テーベ マンドラゴラ(黒)
                int rnd = _random.Next( 3 );
                if ( 1 > rnd )
                {
                    setHiddenStatus( HIDDEN_STATUS_SINK );
                    setStatus( 13 );
                }
            }
            else if ( npcid >= 46125 && npcid <= 46128 )
            {
                setHiddenStatus( L1NpcInstance.HIDDEN_STATUS_ICE );
                setStatus( 4 );
            }
        }

        public void initHideForMinion( L1NpcInstance leader )
        {
            // グループに属するモンスターの出現直後の隠れる動作（リーダーと同じ動作にする）
            int npcid = getNpcTemplate().get_npcId();
            if ( leader.getHiddenStatus() == HIDDEN_STATUS_SINK )
            {
                if ( npcid == 45061 // カーズドスパルトイ
                        || npcid == 45161 // スパルトイ
                        || npcid == 45181 // スパルトイ
                        || npcid == 45455 )
                { // デッドリースパルトイ
                    setHiddenStatus( HIDDEN_STATUS_SINK );
                    setStatus( 13 );
                }
                else if ( npcid == 45045 // クレイゴーレム
                      || npcid == 45126 // ストーンゴーレム
                      || npcid == 45134 // ストーンゴーレム
                      || npcid == 45281 )
                { // ギランストーンゴーレム
                    setHiddenStatus( HIDDEN_STATUS_SINK );
                    setStatus( 4 );
                }
                else if ( npcid == 46107 // テーベ マンドラゴラ(白)
                       || npcid == 46108 )
                { // テーベ マンドラゴラ(黒)
                    setHiddenStatus( HIDDEN_STATUS_SINK );
                    setStatus( 13 );
                }
            }
            else if ( leader.getHiddenStatus() == HIDDEN_STATUS_FLY )
            {
                if ( npcid == 45067 // バレーハーピー
                        || npcid == 45264 // ハーピー
                        || npcid == 45452 // ハーピー
                        || npcid == 45090 // バレーグリフォン
                        || npcid == 45321 // グリフォン
                        || npcid == 45445 )
                { // グリフォン
                    setHiddenStatus( HIDDEN_STATUS_FLY );
                    setStatus( 4 );
                }
                else if ( npcid == 45681 )
                { // リンドビオル
                    setHiddenStatus( HIDDEN_STATUS_FLY );
                    setStatus( 11 );
                }
            }
            else if ( npcid >= 46125 && npcid <= 46128 )
            {
                setHiddenStatus( L1NpcInstance.HIDDEN_STATUS_ICE );
                setStatus( 4 );
            }
        }

        override protected void transform( int transformId )
        {
            base.transform( transformId );

            // DROPの再設定
            getInventory().clearItems();
            DropTable.getInstance().setDrop( this, getInventory() );
            getInventory().shuffle();
        }
    }
}
